#include "SweepWaveform.h"


#include <cmath>
#include <sstream>

#include "Utils.h"

namespace RafMat
{
namespace SimEngine
{

using namespace std;
using namespace SimInterface;

const std::string SweepWaveform::CONF_FREQSTART = "freqSta";
const std::string SweepWaveform::CONF_FREQEND = "freqEnd";
const std::string SweepWaveform::CONF_EXPSWEEP = "expsw";

SweepWaveform::SweepWaveform(SimInterface::ISimulator& sim,
                             double amplitude, double freqSta,
                             double freqEnd)
    : WaveformBase(sim, "Sweep", "sweep", amplitude, 1000, 1, 0),
      m_freqStart(freqSta), m_freqEnd(freqEnd)
{
}

double SweepWaveform::getNextValue()
{
    double currentTime = getCurrentTime();

    // Wartość znormalizowana fazy sygnału.
    // Przedziałowi <0; T> odpowiada <0; 1>, z uwzględnieniem fazy.
    double n = currentTime / getPeriod();
    double ratio = n - floor(n);


    double rate = m_freqEnd / m_freqStart;
    double pha = 2*M_PI* m_freqStart*((pow(rate, ratio) - 1) / log(rate) + getPhase());

    return getGain() * sin(pha) + getOffset();
}

void SweepWaveform::setFreqSta(double freq)
{
    m_freqStart = freq;
}

void SweepWaveform::setFreqEnd(double freq)
{
    m_freqEnd = freq;
}

void SweepWaveform::setExpMode(double expMode)
{
    m_expMode = expMode != 0;
}

bool SweepWaveform::setParameter(const string& param, const string& value) throw(logic_error)
{
    // Usuń ewentualne wiodące i końcowe spacje
    string tparam = Utils::trimWhiteSpaces(param);
    string tvalue = Utils::trimWhiteSpaces(value);

    // Strumień danych dla łańcucha argumentu.
    istringstream istr(tvalue);

    double tmpVal;

    void (SweepWaveform::*setter)(double);

    if(tparam == CONF_FREQSTART)
        setter = &SweepWaveform::setFreqSta;
    else if(tparam == CONF_FREQEND)
        setter = &SweepWaveform::setFreqEnd;
    else if(tparam == CONF_EXPSWEEP)
        setter = &SweepWaveform::setExpMode;
    else
        return WaveformBase::setParameter(param, value);

    istr >> tmpVal;
    if(!istr.bad())
    {
        (this->*setter)(tmpVal);
    }

    if(istr.bad())
    {
        throw iconf_error::syntaxError(*this, tvalue);
    }

    return true;
}

string SweepWaveform::getParameter(const string& param) const throw(logic_error)
{
    // Usuń ewentualne wiodące i końcowe spacje
    string tparam = Utils::trimWhiteSpaces(param);
    string outStr;

    // Strumień danych dla łańcucha argumentu.
    ostringstream ostr(outStr);

    if(tparam == CONF_FREQSTART)
        ostr << getFreqSta();
    else if(tparam == CONF_FREQEND)
        ostr << getFreqEnd();
    else if(tparam == CONF_EXPSWEEP)
        ostr << static_cast<int>(getExpMode());
    else
        return WaveformBase::getParameter(param);

    return ostr.str();
}

SimFile::ConfigWriter& SweepWaveform::dumpParameters(SimFile::ConfigWriter& o) const
{
    WaveformBase::dumpParameters(o);
    o.pushParam(CONF_FREQSTART, getFreqSta());
    o.pushParam(CONF_FREQEND, getFreqEnd());
    o.pushParam(CONF_EXPSWEEP, static_cast<int>(getExpMode()));
    return o;
}

}   // SimEngine namespace
}   // RafMat namespace
